package com.hotel.component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author Str
 * @Date 2021/10/29 9:26
 * @Description :模仿ioc容器
 * {1}提供一个方法 getBean(), 可以根据 id 来获取 Bean 对象。
 * 如: UserServiceImpl, UserDaoImpl
 * {2}在第一次使用时, 从 bean.txt 文本中读取 bean 的配置信息。
 * 将所有的 Bean 生成到类中的 Map 中。
 * {3}以 id 为 key, 对象为 value 保存。
 * {4}后续应用到各个 Controller, Service 中。
 */
public class IocContainer {
    private static Map<String, Object> container = new HashMap<>();

    static {
        //{1}获取类装载器。
        ClassLoader loader = IocContainer.class.getClassLoader();
        //{2}获取 bean.txt 的输入流。
        InputStream is = loader.getResourceAsStream("beans.txt");
        //{3}创建一个 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        try {
            //{4}加载 bean 配置, 创建 bean
            loadConfig(br);
            br.close();
        } catch (ClassNotFoundException | InstantiationException |
                IllegalAccessException | IOException e) {
            System.out.println("{IOC Container} IOC 初始化异常....");
            e.printStackTrace();
        }
    }

    /**
     * 反射创建对象
     * @return void
     */
    public static void loadConfig(BufferedReader reader)
            throws IOException, ClassNotFoundException,
            InstantiationException, IllegalAccessException {
        String line = null;
        while ((line = reader.readLine()) != null) {
            //{1}加载配置, 读取 bean 信息
            Bean bean = new Bean(line);
            //{2}根据 clsPath 获取字节码。
            Class<?> clz = Class.forName(bean.clsPath);
            //{3}创建这个 bean 对象。
            Object beanObj = clz.newInstance();
            //{4}存入 ioc 容器。
            container.put(bean.className, beanObj);
        }
        System.out.println("{IOC Container} 创建了 " + container);
    }

    /**
     * 静态内部类，获取类名和类路径
     */
    static class Bean {
        String className;
        String clsPath;

        public Bean(String line) {
            String[] data = line.split("=");
            this.className = data[0];
            this.clsPath = data[1];
        }
    }

    //{3}getBean(传入id) 你要用，找我来拿。
    public static Object getBean(String className) {
        //{1}从容器中取 bean 对象
        //   [UserServiceImpl, UserDaoImpl]
        Object obj = container.get(className);
        if (obj == null) {
            throw new RuntimeException("获取 Bean 失败。");
        }
        return obj;
    }

//    public static void main(String[] args) {
//        Object o1 = IocContainer.getBean("userService");
//        System.out.println( o1 );
//    }
}
